package com.hub.videobrowsdownload

import android.content.ContentValues
import android.content.Context
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.forest.download.State
import com.forest.download.download
import com.security.brows.room.BrowsRoomHelper
import com.security.brows.room.BrowsVideoDownloadBean

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.IOException
import java.net.URLConnection
import java.nio.file.Files
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.roundToLong


class BrowsMyViewModel : ViewModel() {

    val TAG = "DOWNLOAD_MODEL"

    val isDarkTheme = MutableLiveData<Boolean>(false)
    fun onCreate(context: Context) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val downloading = BrowsRoomHelper.getDao(context).getDownloadingVideo()
                if (downloading.isNotEmpty()) {
                    for (i in downloading) {
                        val toVideoPrepare = i.toVideoPrepare()
                        if (toVideoPrepare != null) {
                            startDownload(context, toVideoPrepare)
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

    }

    val downloadingTaskMap = ConcurrentHashMap<String, BrowsVideoPrepare>()
    val downloadingTaskSize = MutableLiveData<Int>(0)

    fun rmDownloading(context: Context, videoPrepare: BrowsVideoPrepare) {
        try {
            videoPrepare.downloadWrapper.value?.task?.remove()
            downloadingTaskMap.remove(videoPrepare.url)
            downloadingTaskSize.value = downloadingTaskMap.size
            try {
                deleteDir(
                    BrowsM3U8Helper.getDownloadFileParentDir(
                        context,
                        videoPrepare.getVideoId()
                    )
                )
            } catch (e: Exception) {
                e.printStackTrace()
            }
            BrowsRoomHelper.getDao().deleteById(videoPrepare.getVideoId())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun rmDownloaded(context: Context, downloadBean: BrowsVideoDownloadBean) {
        try {
            val a = downloadingTaskMap.remove(downloadBean.url)
            a?.downloadWrapper?.value?.task?.remove()
            downloadingTaskSize.value = downloadingTaskMap.size
        } catch (e: Exception) {
            e.printStackTrace()
        }
        try {
            try {
                val thumbPath = downloadBean.thumbPath
                if (!thumbPath.isNullOrEmpty()) {
                    val thumbFile = File(downloadBean.thumbPath!!)
                    thumbFile.delete()
                }
            } catch (e: Exception) {

            }
            try {
                val downloadFilePath = downloadBean.downloadFilePath
                if (!downloadFilePath.isNullOrEmpty()) {
                    val file = File(downloadFilePath)
                    file.delete()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            try {
                deleteDir(BrowsM3U8Helper.getDownloadFileParentDir(context, downloadBean.id))
            } catch (e: Exception) {
                e.printStackTrace()
            }
            BrowsRoomHelper.getDao().deleteById(downloadBean.id)
        } catch (e: Exception) {

        }
    }

    // 递归计算文件夹大小
    fun getFolderSize(folder: File): Long {
        var size: Long = 0

        if (folder.isDirectory) {
            val files = folder.listFiles()
            files?.let {
                for (file in it) {
                    size += if (file.isFile) {
                        file.length()
                    } else {
                        getFolderSize(file)
                    }
                }
            }
        } else {
            size = folder.length()
        }

        return size
    }

    fun startDownload(context: Context, videoPrepare: BrowsVideoPrepare): BrowsVideoPrepare {
        videoPrepare.getVideoId()
        try {
            // 避免重复下载
            if (BrowsRoomHelper.getDao(context).getDownloadedVideoByUrl(videoPrepare.url)!= null){
                return videoPrepare
            }
            if (downloadingTaskMap.containsKey(videoPrepare.url)) {
                val get = downloadingTaskMap.get(videoPrepare.url)
                val task = get?.downloadWrapper?.value?.task
                if (task?.isFailed() == true) {
                    task.remove(false)
                    downloadingTaskMap.remove(get.url)
                    videoPrepare.downloadSpeedLength.postValue(0L)
                } else {
                    return get!!
                }
            }
        } catch (e: Exception) {

        }
        Log.d(TAG, "START: ${videoPrepare.url}")
        //   addHeader(
        //                    "User-Agent",
        //                    "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
        //                )
        val downloadFile = videoPrepare.getDownloadFile(context)
        Log.i("FileNameLoooong___", downloadFile.absolutePath)
        val task = CoroutineScope(Dispatchers.IO).download(
            videoPrepare.url,
            downloadFile.name,
            downloadFile.parentFile?.absolutePath ?: context.cacheDir.absolutePath
        )
//        task.progress().onEach {
//            try {
//                videoPrepare.downloadWrapper.postValue(DownLoadWrapper(task, task.getState()))
//            } catch (e: Exception) {
//                e.printStackTrace()
//            }
//        }.launchIn(viewModelScope)
        task.state(1000).onEach { state ->


            try {

                videoPrepare.downloadWrapper.value =
                    (BrowsDownLoadWrapper(task, state, System.currentTimeMillis()))
                var stateMessage = "ELSE"
                when (state) {
                    is State.None -> { // text.value = "下载"
                        videoPrepare.downloadSpeedStartTime = 0
                        videoPrepare.downloadSpeedLength.value = 0
                        stateMessage = "None"
                    }

                    is State.Waiting -> {
                        videoPrepare.downloadSpeedStartTime = 0
                        videoPrepare.downloadSpeedLength.value = 0
                        //    text.value = "等待中"
                        stateMessage = "Waiting"
                    }

                    is State.Downloading -> {
                        try {
                            if (videoPrepare.downloadSpeedStartTime == 0L) {
                                videoPrepare.downloadSpeedStartTime = System.currentTimeMillis()
                                videoPrepare.downloadSpeedStartSize =
                                    getFolderSize(videoPrepare.getDownloadFile(context).parentFile)
//                                Log.i("下载速度", "从头算起")
                            } else {
                                val dTime =
                                    (System.currentTimeMillis() - videoPrepare.downloadSpeedStartTime) / 1000f
                                var dSize =
                                    getFolderSize(videoPrepare.getDownloadFile(context).parentFile) - videoPrepare.downloadSpeedStartSize
                                if (dSize < 0) {
                                    dSize = 0
                                }
                                val roundToLong = (dSize / dTime).roundToLong()
                                videoPrepare.downloadSpeedLength.value = roundToLong
//                                Log.i("下载速度", "${state.progress.downloadSize} $dTime $dSize $roundToLong")
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }
                        stateMessage = "Downloading"
                        // text.value = state.progress.percentStr()
                        // 更新进度
                        // progress.value = state.progress.progress()
                    }

                    is State.Failed -> { // text.value = "重试"
                        videoPrepare.downloadSpeedStartTime = 0
                        videoPrepare.downloadSpeedLength.value = 0
                        stateMessage = "Failed"

                    }

                    is State.Stopped -> {// text.value = "继续"
                        videoPrepare.downloadSpeedStartTime = 0
                        videoPrepare.downloadSpeedLength.value = 0
                        stateMessage = "Stopped"
                    }

                    is State.Succeed -> {// text.value = "完成"

                        videoPrepare.downloadSuccessTime = System.currentTimeMillis()
                        try {
                            BrowsVideoDownloadBean().save(context, videoPrepare)
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }
                        stateMessage = "Succeed"
                        downloadingTaskMap.remove(videoPrepare.url)
                        try {
                            downloadingTaskSize.value = downloadingTaskMap.size
                        } catch (e: Exception) {
                            e.printStackTrace()

                        }


                    }
                }
                Log.d(
                    TAG,
                    "${stateMessage} ${task.isStarted()} ${task.isFailed()} ${state.progress.percentStr()} ${state.progress.downloadSize}/${state.progress.totalSize}"
                )
                try {
                    if (downloadingTaskMap.containsKey(videoPrepare.url)) {
                        BrowsVideoDownloadBean().save(context, videoPrepare)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }.launchIn(viewModelScope)

        videoPrepare.downloadWrapper.postValue(
            BrowsDownLoadWrapper(
                task,
                State.Waiting(),
                System.currentTimeMillis()
            )
        )
        task.start()
        downloadingTaskMap[videoPrepare.url] = videoPrepare
        try {
            downloadingTaskSize.postValue(downloadingTaskMap.size)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        CoroutineScope(Dispatchers.IO).launch {
            videoPrepare.changeThumbToDownloadFileDir(context)
            BrowsVideoDownloadBean().save(context, videoPrepare)
        }
        return videoPrepare
    }


    override fun onCleared() {
        onDestroy()
        super.onCleared()
    }

    fun onDestroy() {
        try {
            downloadingTaskMap.clear()
            downloadingTaskSize.value = 0
        } catch (e: Exception) {
        }
        try {
            clearAllCache(BrowsApplication.context)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun deleteDir(dir: File?): Boolean {
        if (dir != null && dir.isDirectory) {
            val children = dir.list()
            if (children != null) {
                for (i in children.indices) {
                    val success = deleteDir(File(dir, children[i]))
                    if (!success) {
                        return false
                    }
                }
            }
        }
        if (dir?.name?.startsWith("download_") == true) {
            return true
        }
        return dir!!.delete()
    }

    fun clearAllCache(context: Context) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                if (BrowsRoomHelper.getDao(context).getDownloadingVideo().isEmpty()) {
                    deleteDir(context.cacheDir)
                    if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
                        deleteDir(context.externalCacheDir)
                    }
                }
            } catch (e: Exception) {
            }
        }
    }


    suspend fun saveFileToSdcard(context: Context, file: File, parentName: String) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 获取公共媒体目录的 Uri
            val sdcardUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
            // 创建 ContentValues 对象，用于指定文件属性
            val contentValues = ContentValues()
            contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, file.name)
            var MIME_TYPE: String? = null
            MIME_TYPE = try {
                URLConnection.guessContentTypeFromName(file.name)
            } catch (e: java.lang.Exception) {
                "*/*"
            }

            Log.i(TAG, "MIME_TYPE: $MIME_TYPE")
            contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, MIME_TYPE)
            contentValues.put(
                MediaStore.Files.FileColumns.RELATIVE_PATH,
                Environment.DIRECTORY_DOWNLOADS + File.separator + parentName
            )

            // 插入文件到公共媒体目录
            val resolver = context.contentResolver
            val uri = resolver.insert(sdcardUri, contentValues)
            if (uri != null) {
                try {
                    // 打开输出流
                    val outputStream = resolver.openOutputStream(uri)
                    val inputStream = Files.newInputStream(file.toPath())
                    val buffer = ByteArray(4096)
                    var len: Int
                    while (inputStream.read(buffer).also { len = it } != -1) {
                        outputStream!!.write(buffer, 0, len)
                    }

                    // 关闭输出流和输入流
                    outputStream?.close()
                    inputStream.close()
                } catch (e: IOException) {
                    Log.e(TAG, "saveFileToSdcard", e)
                }

                // 通过 Uri 获取文件的路径
                try {
                    context.contentResolver.query(uri, null, null, null, null).use { cursor ->
                        if (cursor != null && cursor.moveToFirst()) {
                            val pathIndex =
                                cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)
                            val filePath = cursor.getString(pathIndex)
                            Log.i(TAG, "SD文件存储成功: " + filePath)

                            withContext(Dispatchers.Main) {
                                Toast.makeText(
                                    BrowsApplication.context,
                                    "SD文件存储成功: $filePath",
                                    Toast.LENGTH_LONG
                                ).show()
                            }
                        }
                    }
                } catch (e: java.lang.Exception) {
                    Log.e(TAG, "SD文件存储成功", e)
                }

            }
        }
    }
}